Skip to content

Implement priority and tag selection in task creation version 1#31

Merged
tqha1011 merged 5 commits intomainfrom
priority_selector_and_tag_system
Apr 9, 2026
Merged

Implement priority and tag selection in task creation version 1#31
tqha1011 merged 5 commits intomainfrom
priority_selector_and_tag_system

Conversation

@anhkietbienhoa-crypto
Copy link
Copy Markdown
Collaborator

@anhkietbienhoa-crypto anhkietbienhoa-crypto commented Apr 9, 2026

Thử nghiệm

Summary by CodeRabbit

  • New Features

    • Tasks can have priorities (low/medium/high/urgent) and tags with visual indicators
    • Priority and tag selectors added to task creation; created tasks persist with selected priority/tags
    • Home screen groups tasks by priority with per-group headers, empty-state handling, plus priority filter chips and a sort toggle
  • Documentation

    • README streamlined to summarize project and new task features

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 9, 2026

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Walkthrough

Added priority and tag data to the task model, a TaskViewModel for state, priority/tag selector widgets, integrated selectors into task creation, and reworked the home screen to consume the view model with grouping, filtering, and sorting by priority. README shortened accordingly.

Changes

Cohort / File(s) Summary
Core Model Definitions
src/lib/features/tasks/model/task_model.dart
Added Priority enum and PriorityExtension (label/color/icon), introduced TagModel, and extended TaskModel with priority and tags fields plus constructor updates.
State Management
src/lib/features/tasks/viewmodel/task_viewmodel.dart
New TaskViewModel (extends ChangeNotifier) managing selected priority/tags, available tags, tasks collection, filtering by priority/tag, optional priority sorting, and mutation APIs (setPriority, toggleTag, addTask, reset, setFilterPriority, setFilterTag, toggleSortByPriority).
UI Selection Widgets
src/lib/features/tasks/view/widgets/priority_selector.dart, src/lib/features/tasks/view/widgets/tag_selector.dart
Added PrioritySelector (animated selectable priority cards) and TagSelector (selectable tag pills) that read and mutate TaskViewModel via context.watch/calls.
Screen Integration
src/lib/features/tasks/view/screens/create_task_screen.dart, src/lib/features/tasks/view/screens/home_screen.dart
CreateTaskScreen now includes PrioritySelector and TagSelector, builds TaskModel with priority/tags and uses TaskViewModel.addTask then reset() and Navigator.pop. HomeScreen now consumes TaskViewModel, groups tasks by Priority, shows grouped lists with headers, adds filter/sort controls, and empty-state handling.
App Setup
src/lib/main.dart
Added TaskViewModel provider wiring and provider imports (wrapped app with ChangeNotifierProvider<TaskViewModel>). Minor formatting changes.
Documentation
README.md
Condensed README, replaced original overview with brief bullet summary of the added priority/tag features and embedded image.

Sequence Diagram

sequenceDiagram
    participant User
    participant UI as CreateTaskScreen
    participant VM as TaskViewModel
    participant Model as TaskModel

    User->>UI: Open create task screen
    UI->>VM: context.watch<TaskViewModel>()
    VM-->>UI: selectedPriority, availableTags

    User->>UI: Tap priority card
    UI->>VM: setPriority(priority)
    VM->>VM: update selectedPriority, notifyListeners()
    VM-->>UI: rebuild (new selection)

    User->>UI: Tap tag pill
    UI->>VM: toggleTag(tag)
    VM->>VM: add/remove tag, notifyListeners()
    VM-->>UI: rebuild (tag selection)

    User->>UI: Fill fields and tap Create
    UI->>Model: Construct TaskModel(title, desc, priority, tags, ...)
    UI->>VM: addTask(newTask)
    VM->>VM: append to _tasks, notifyListeners()
    VM->>VM: reset() selectedPriority/tags
    UI->>User: Navigator.pop(context)
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested Reviewers

  • hoanghaoz

Poem

🐰 With a twitch of whiskers, I declare—

Priorities set with tender care.
Tags tucked in like carrots neat,
Tasks sorted tidy, hopping fleet.
Hooray! A burrow of order, sweet.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures the main objective of the PR: implementing priority and tag selection in task creation.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch priority_selector_and_tag_system

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/lib/main.dart (1)

21-25: ⚠️ Potential issue | 🔴 Critical

Fail fast when Supabase config is missing.

Line 21 detects empty credentials but line 25 still initializes Supabase with them. This allows the app to start in a broken state where subsequent Supabase operations fail silently at runtime. The empty string credentials are then accessed by downstream code without validation, leading to cascading failures in auth_gate, statistics_service, and other services that depend on a properly initialized client.

Suggested fix
   if (supabaseUrl.isEmpty || supabaseAnonKey.isEmpty) {
-    debugPrint('Error: SUPABASE_URL or SUPABASE_ANON_KEY is missing');
+    throw StateError('SUPABASE_URL or SUPABASE_ANON_KEY is missing');
   }
 
   await Supabase.initialize(url: supabaseUrl, anonKey: supabaseAnonKey);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/main.dart` around lines 21 - 25, The code logs missing Supabase
credentials but still calls Supabase.initialize with empty strings; update the
startup check in main (the supabaseUrl / supabaseAnonKey validation) to fail
fast by throwing an exception or terminating startup instead of
continuing—replace the debugPrint-only behavior with a thrown StateError or
process exit when supabaseUrl.isEmpty || supabaseAnonKey.isEmpty so
Supabase.initialize is never invoked with invalid values; keep the validation
tied to the same symbols (supabaseUrl, supabaseAnonKey, Supabase.initialize) so
downstream services (auth_gate, statistics_service) never run against an
uninitialized client.
🧹 Nitpick comments (2)
src/lib/features/tasks/view/screens/home_screen.dart (1)

16-25: Cache viewModel.tasks before grouping.

viewModel.tasks recomputes filtering/sorting every time the getter is read. The current loop does that once per priority bucket on every rebuild.

Suggested refactor
-    Map<Priority, List<TaskModel>> grouped = {};
-    for (var priority in Priority.values.reversed) {
-      final tasks = viewModel.tasks
+    final visibleTasks = viewModel.tasks;
+    final Map<Priority, List<TaskModel>> grouped = {};
+    for (final priority in Priority.values.reversed) {
+      final tasks = visibleTasks
           .where((t) => t.priority == priority)
           .toList();
       if (tasks.isNotEmpty) grouped[priority] = tasks;
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/features/tasks/view/screens/home_screen.dart` around lines 16 - 25,
Cache the TaskViewModel.tasks result into a local variable before grouping to
avoid re-evaluating the getter on each priority iteration: call the getter once
(e.g., final allTasks = viewModel.tasks) and then use allTasks.where(...) inside
the loop that builds grouped (using Priority.values.reversed, grouped Map, and
the existing TaskModel/priority checks) so the expensive filtering/sorting is
not recomputed per priority.
src/lib/features/tasks/viewmodel/task_viewmodel.dart (1)

6-18: Hide availableTags behind an unmodifiable getter.

Right now any caller can mutate the tag catalog directly and bypass notifyListeners(). Making the list private and exposing List.unmodifiable(...) keeps the view model as the single mutation point.

Suggested refactor
-  final List<TagModel> availableTags = [
+  final List<TagModel> _availableTags = [
     TagModel(id: 'work', name: 'Work', color: const Color(0xFF2196F3)),
     TagModel(id: 'study', name: 'Study', color: const Color(0xFF9C27B0)),
     TagModel(id: 'personal', name: 'Personal', color: const Color(0xFF4CAF50)),
     TagModel(id: 'project', name: 'Project', color: const Color(0xFFFF9800)),
   ];
+
+  List<TagModel> get availableTags => List.unmodifiable(_availableTags);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/features/tasks/viewmodel/task_viewmodel.dart` around lines 6 - 18,
Make the public mutable availableTags list private and expose it via an
unmodifiable getter: rename availableTags to _availableTags (keep its initial
TagModel entries), and add a getter List<TagModel> get availableTags =>
List.unmodifiable(_availableTags); this ensures callers cannot mutate the
catalog directly (forcing mutations through the viewmodel and notifyListeners)
while leaving selectedPriority, _selectedTags, and the selectedTags getter
unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/lib/features/tasks/view/screens/create_task_screen.dart`:
- Around line 266-289: Before calling viewModel.addTask(...) in the onPressed
handler, validate that _endTime is after _startTime (not equal or earlier); if
the check fails, do not call viewModel.addTask or viewModel.reset, and instead
show user feedback (e.g., ScaffoldMessenger.of(context).showSnackBar or similar)
explaining the time range is invalid. Update the onPressed block in
create_task_screen.dart around the existing onPressed closure so it checks
_startTime and _endTime, returns early on invalid range, and only constructs
TaskModel and calls TaskViewModel.addTask/reset when the times are valid.
- Around line 105-121: The onSelected handler for the ChoiceChip is resetting
_selectedCategoryIndex to 0 when a selected chip is tapped (false branch) which
forces the category back to "Development"; change the handler in the ChoiceChip
that references _selectedCategoryIndex so it only updates state when selected ==
true (e.g., inside setState assign _selectedCategoryIndex = index when selected)
and ignore the false case (do not reset to 0) so deselecting does not overwrite
the previously chosen category.
- Around line 145-150: TaskViewModel is app-scoped so previous selections
persist; call TaskViewModel.reset() when the form opens (not only on successful
create). Add a reset invocation in the screen's entry point—e.g. in
CreateTaskScreen's initState() (or the equivalent hook where the widget is
created) call context.read<TaskViewModel>().reset() (or
ref.read(TaskViewModel).reset() depending on your provider API) so
PrioritySelector and TagSelector start with a clean state whenever the form is
presented.

In `@src/lib/features/tasks/view/screens/home_screen.dart`:
- Around line 149-190: Replace the raw GestureDetector + AnimatedContainer used
for the sort control with a semantic, focusable Material widget such as
FilterChip or ChoiceChip (or wrap the AnimatedContainer with InkWell inside a
Material) so it supports keyboard navigation, focus/pressed states and
accessibility semantics; specifically change the GestureDetector that calls
viewModel.toggleSortByPriority() to use a FilterChip/ChoiceChip (or InkWell in
Material) and map its selected state to viewModel.sortByPriority and its
onSelected/onChanged to viewModel.toggleSortByPriority(), and do the same
replacement for the custom _FilterChip so both controls gain proper
focusability, pressed visuals and accessibility labels instead of relying on
GestureDetector.

In `@src/lib/features/tasks/view/widgets/priority_selector.dart`:
- Around line 18-57: Replace the custom GestureDetector+AnimatedContainer
implementation with a proper selectable Material control (e.g., ChoiceChip)
inside the Priority.values.map so keyboard and screen-reader interaction are
automatic; for each priority, use ChoiceChip with selected:
viewModel.selectedPriority == priority, onSelected: (_) =>
viewModel.setPriority(priority), avatar/icon using priority.icon, label using
priority.label, and apply selectedColor: priority.color and backgroundColor:
Color(0xFFF1F7FD) plus a rounded shape/border to match the current visuals—this
keeps the Priority.values mapping, viewModel.setPriority, and
viewModel.selectedPriority references while providing built-in semantics and
keyboard support.

In `@src/lib/features/tasks/view/widgets/tag_selector.dart`:
- Around line 17-55: Replace the custom GestureDetector + AnimatedContainer tag
widgets with Flutter's FilterChip to restore proper accessibility and
focus/selection semantics: in the Wrap over viewModel.availableTags (where you
currently call viewModel.isTagSelected(tag) and viewModel.toggleTag(tag)),
render a FilterChip per tag with selected set from viewModel.isTagSelected(tag),
onSelected calling viewModel.toggleTag(tag), label using Text(tag.name) and
styling via selectedColor (tag.color), backgroundColor
(tag.color.withOpacity(0.1)), labelStyle (use white when selected, tag.color
when not), padding and shape (BorderRadius.circular(20)) to match current
visuals, and optionally provide a selectedIcon (Icons.check) to mimic the
existing check display.

---

Outside diff comments:
In `@src/lib/main.dart`:
- Around line 21-25: The code logs missing Supabase credentials but still calls
Supabase.initialize with empty strings; update the startup check in main (the
supabaseUrl / supabaseAnonKey validation) to fail fast by throwing an exception
or terminating startup instead of continuing—replace the debugPrint-only
behavior with a thrown StateError or process exit when supabaseUrl.isEmpty ||
supabaseAnonKey.isEmpty so Supabase.initialize is never invoked with invalid
values; keep the validation tied to the same symbols (supabaseUrl,
supabaseAnonKey, Supabase.initialize) so downstream services (auth_gate,
statistics_service) never run against an uninitialized client.

---

Nitpick comments:
In `@src/lib/features/tasks/view/screens/home_screen.dart`:
- Around line 16-25: Cache the TaskViewModel.tasks result into a local variable
before grouping to avoid re-evaluating the getter on each priority iteration:
call the getter once (e.g., final allTasks = viewModel.tasks) and then use
allTasks.where(...) inside the loop that builds grouped (using
Priority.values.reversed, grouped Map, and the existing TaskModel/priority
checks) so the expensive filtering/sorting is not recomputed per priority.

In `@src/lib/features/tasks/viewmodel/task_viewmodel.dart`:
- Around line 6-18: Make the public mutable availableTags list private and
expose it via an unmodifiable getter: rename availableTags to _availableTags
(keep its initial TagModel entries), and add a getter List<TagModel> get
availableTags => List.unmodifiable(_availableTags); this ensures callers cannot
mutate the catalog directly (forcing mutations through the viewmodel and
notifyListeners) while leaving selectedPriority, _selectedTags, and the
selectedTags getter unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 419ac100-97fd-4942-9166-bde14c25d86a

📥 Commits

Reviewing files that changed from the base of the PR and between c8c7e6d and 5c505c7.

📒 Files selected for processing (8)
  • README.md
  • src/lib/features/tasks/model/task_model.dart
  • src/lib/features/tasks/view/screens/create_task_screen.dart
  • src/lib/features/tasks/view/screens/home_screen.dart
  • src/lib/features/tasks/view/widgets/priority_selector.dart
  • src/lib/features/tasks/view/widgets/tag_selector.dart
  • src/lib/features/tasks/viewmodel/task_viewmodel.dart
  • src/lib/main.dart

Comment on lines +105 to +121
List<String> categories = [
'Development',
'Research',
'Design',
'Backend',
];
bool isSelected = index == _selectedCategoryIndex;
return Padding(
padding: const EdgeInsets.only(right: 10),
child: ChoiceChip(
label: Text(categories[index]),
selected: isSelected,
onSelected: (selected) => setState(() => _selectedCategoryIndex = selected ? index : 0),
onSelected: (selected) => setState(
() => _selectedCategoryIndex = selected
? index
: 0,
),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Don't reset the category to index 0 on deselect.

Tapping an already-selected chip currently changes the task category back to Development. For a single-select control, the false branch should usually be ignored instead of silently rewriting the value.

Suggested fix
-                              onSelected: (selected) => setState(
-                                () => _selectedCategoryIndex = selected
-                                    ? index
-                                    : 0,
-                              ),
+                              onSelected: (selected) {
+                                if (!selected) return;
+                                setState(() => _selectedCategoryIndex = index);
+                              },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
List<String> categories = [
'Development',
'Research',
'Design',
'Backend',
];
bool isSelected = index == _selectedCategoryIndex;
return Padding(
padding: const EdgeInsets.only(right: 10),
child: ChoiceChip(
label: Text(categories[index]),
selected: isSelected,
onSelected: (selected) => setState(() => _selectedCategoryIndex = selected ? index : 0),
onSelected: (selected) => setState(
() => _selectedCategoryIndex = selected
? index
: 0,
),
List<String> categories = [
'Development',
'Research',
'Design',
'Backend',
];
bool isSelected = index == _selectedCategoryIndex;
return Padding(
padding: const EdgeInsets.only(right: 10),
child: ChoiceChip(
label: Text(categories[index]),
selected: isSelected,
onSelected: (selected) {
if (!selected) return;
setState(() => _selectedCategoryIndex = index);
},
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/features/tasks/view/screens/create_task_screen.dart` around lines 105
- 121, The onSelected handler for the ChoiceChip is resetting
_selectedCategoryIndex to 0 when a selected chip is tapped (false branch) which
forces the category back to "Development"; change the handler in the ChoiceChip
that references _selectedCategoryIndex so it only updates state when selected ==
true (e.g., inside setState assign _selectedCategoryIndex = index when selected)
and ignore the false case (do not reset to 0) so deselecting does not overwrite
the previously chosen category.

Comment on lines +145 to +150
// ─── PRIORITY SELECTOR (MỚI) ──────────────
const PrioritySelector(),
const SizedBox(height: 20),

// ─── TAG SELECTOR (MỚI) ───────────────────
const TagSelector(),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's check if main.dart exists and look for TaskViewModel provision
find . -type f -name "main.dart" | head -5

Repository: tqha1011/TaskManagement

Length of output: 86


🏁 Script executed:

# Search for TaskViewModel provider setup
rg -i "taskviewmodel" --type dart | head -20

Repository: tqha1011/TaskManagement

Length of output: 857


🏁 Script executed:

# Check the create_task_screen.dart file structure
cat -n src/lib/features/tasks/view/screens/create_task_screen.dart | head -50

Repository: tqha1011/TaskManagement

Length of output: 2234


🏁 Script executed:

# Search for reset() calls in create_task_screen.dart
rg "reset" src/lib/features/tasks/view/screens/create_task_screen.dart -n

Repository: tqha1011/TaskManagement

Length of output: 115


🏁 Script executed:

# Read lines 140-160 to see context around lines 145-150
sed -n '140,160p' src/lib/features/tasks/view/screens/create_task_screen.dart

Repository: tqha1011/TaskManagement

Length of output: 843


🏁 Script executed:

# Read lines 260-295 to see the "Also applies to" section
sed -n '260,295p' src/lib/features/tasks/view/screens/create_task_screen.dart

Repository: tqha1011/TaskManagement

Length of output: 1820


🏁 Script executed:

# Check main.dart for the full provider setup and scope
cat -n src/lib/main.dart | grep -A 10 -B 5 "TaskViewModel"

Repository: tqha1011/TaskManagement

Length of output: 702


🏁 Script executed:

# Check if there's an initState() method already in _CreateTaskScreenState
sed -n '19,100p' src/lib/features/tasks/view/screens/create_task_screen.dart | grep -A 5 "initState"

Repository: tqha1011/TaskManagement

Length of output: 49


🏁 Script executed:

# Look at the full dispose/lifecycle methods
rg "dispose|initState|deactivate" src/lib/features/tasks/view/screens/create_task_screen.dart -A 3

Repository: tqha1011/TaskManagement

Length of output: 49


🏁 Script executed:

# Get more context around where reset() is called - show the full button handler
sed -n '265,300p' src/lib/features/tasks/view/screens/create_task_screen.dart

Repository: tqha1011/TaskManagement

Length of output: 1865


🏁 Script executed:

# Check TaskViewModel.reset() method to understand what it does
rg -A 10 "void reset" src/lib/features/tasks/viewmodel/task_viewmodel.dart

Repository: tqha1011/TaskManagement

Length of output: 337


🏁 Script executed:

# Check if there's any WillPopScope or onBack handling
rg "WillPopScope|onPopInvoked|pop|Navigator" src/lib/features/tasks/view/screens/create_task_screen.dart -n

Repository: tqha1011/TaskManagement

Length of output: 184


🏁 Script executed:

# Let's see the entire _CreateTaskScreenState class to understand its full structure
wc -l src/lib/features/tasks/view/screens/create_task_screen.dart

Repository: tqha1011/TaskManagement

Length of output: 130


🏁 Script executed:

# Read more of the file to see if there are any other reset patterns
sed -n '1,50p' src/lib/features/tasks/view/screens/create_task_screen.dart

Repository: tqha1011/TaskManagement

Length of output: 1884


🏁 Script executed:

# Check how the CreateTaskScreen is navigated to
rg "CreateTaskScreen" src/lib/features/tasks/view/screens/ -n

Repository: tqha1011/TaskManagement

Length of output: 667


🏁 Script executed:

# Check the back button at line 64 - what does it do exactly?
sed -n '55,75p' src/lib/features/tasks/view/screens/create_task_screen.dart

Repository: tqha1011/TaskManagement

Length of output: 926


🏁 Script executed:

# Check if PrioritySelector and TagSelector have their own state management
cat -n src/lib/features/tasks/view/widgets/priority_selector.dart | head -40

Repository: tqha1011/TaskManagement

Length of output: 1959


🏁 Script executed:

# Look for any other screens or routes that might open CreateTaskScreen
rg "CreateTaskScreen\|push\|pushNamed" src/lib/features/tasks/view/screens/home_screen.dart -B 2 -A 2

Repository: tqha1011/TaskManagement

Length of output: 49


Reset provider state when the form opens.

TaskViewModel is app-scoped in src/lib/main.dart. The back button (line 64) closes the form without calling reset(), so previously selected priority/tags persist when the form reopens. Only the successful create path (line 287) calls reset().

Suggested fix
 class _CreateTaskScreenState extends State<CreateTaskScreen> {
+  `@override`
+  void initState() {
+    super.initState();
+    WidgetsBinding.instance.addPostFrameCallback((_) {
+      if (mounted) context.read<TaskViewModel>().reset();
+    });
+  }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/features/tasks/view/screens/create_task_screen.dart` around lines 145
- 150, TaskViewModel is app-scoped so previous selections persist; call
TaskViewModel.reset() when the form opens (not only on successful create). Add a
reset invocation in the screen's entry point—e.g. in CreateTaskScreen's
initState() (or the equivalent hook where the widget is created) call
context.read<TaskViewModel>().reset() (or ref.read(TaskViewModel).reset()
depending on your provider API) so PrioritySelector and TagSelector start with a
clean state whenever the form is presented.

Comment on lines +266 to +289
onPressed: () {
final viewModel = context.read<TaskViewModel>();
final List<String> categories = [
'Development',
'Research',
'Design',
'Backend',
];
final newTask = TaskModel(
id: DateTime.now().millisecondsSinceEpoch
.toString(),
title: _nameController.text,
description: _descController.text,
category: categories[_selectedCategoryIndex],
startTime: _startTime,
endTime: _endTime,
date: _selectedDate,
priority: viewModel.selectedPriority,
tags: List.from(viewModel.selectedTags),
);
viewModel.addTask(newTask);
viewModel.reset();
Navigator.pop(context);
},
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Validate the time range before creating the task.

Nothing prevents endTime from being earlier than or equal to startTime, so this can save impossible tasks. Guard it before addTask(...) and show feedback instead of creating the item.

Suggested fix
                         onPressed: () {
                           final viewModel = context.read<TaskViewModel>();
+                          final startMinutes =
+                              _startTime.hour * 60 + _startTime.minute;
+                          final endMinutes =
+                              _endTime.hour * 60 + _endTime.minute;
+                          if (endMinutes <= startMinutes) {
+                            ScaffoldMessenger.of(context).showSnackBar(
+                              const SnackBar(
+                                content: Text('End time must be after start time'),
+                              ),
+                            );
+                            return;
+                          }
                           final List<String> categories = [
                             'Development',
                             'Research',
                             'Design',
                             'Backend',
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
onPressed: () {
final viewModel = context.read<TaskViewModel>();
final List<String> categories = [
'Development',
'Research',
'Design',
'Backend',
];
final newTask = TaskModel(
id: DateTime.now().millisecondsSinceEpoch
.toString(),
title: _nameController.text,
description: _descController.text,
category: categories[_selectedCategoryIndex],
startTime: _startTime,
endTime: _endTime,
date: _selectedDate,
priority: viewModel.selectedPriority,
tags: List.from(viewModel.selectedTags),
);
viewModel.addTask(newTask);
viewModel.reset();
Navigator.pop(context);
},
onPressed: () {
final viewModel = context.read<TaskViewModel>();
final startMinutes =
_startTime.hour * 60 + _startTime.minute;
final endMinutes =
_endTime.hour * 60 + _endTime.minute;
if (endMinutes <= startMinutes) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('End time must be after start time'),
),
);
return;
}
final List<String> categories = [
'Development',
'Research',
'Design',
'Backend',
];
final newTask = TaskModel(
id: DateTime.now().millisecondsSinceEpoch
.toString(),
title: _nameController.text,
description: _descController.text,
category: categories[_selectedCategoryIndex],
startTime: _startTime,
endTime: _endTime,
date: _selectedDate,
priority: viewModel.selectedPriority,
tags: List.from(viewModel.selectedTags),
);
viewModel.addTask(newTask);
viewModel.reset();
Navigator.pop(context);
},
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/features/tasks/view/screens/create_task_screen.dart` around lines 266
- 289, Before calling viewModel.addTask(...) in the onPressed handler, validate
that _endTime is after _startTime (not equal or earlier); if the check fails, do
not call viewModel.addTask or viewModel.reset, and instead show user feedback
(e.g., ScaffoldMessenger.of(context).showSnackBar or similar) explaining the
time range is invalid. Update the onPressed block in create_task_screen.dart
around the existing onPressed closure so it checks _startTime and _endTime,
returns early on invalid range, and only constructs TaskModel and calls
TaskViewModel.addTask/reset when the times are valid.

Comment on lines +149 to 190
GestureDetector(
onTap: () => viewModel.toggleSortByPriority(),
child: AnimatedContainer(
duration: const Duration(milliseconds: 200),
padding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 7,
),
decoration: BoxDecoration(
color: viewModel.sortByPriority
? AppColors.primaryBlue
: Colors.white,
borderRadius: BorderRadius.circular(20),
border: Border.all(
color: AppColors.primaryBlue,
width: 1,
),
),
child: Row(
children: [
Icon(
Icons.sort,
size: 16,
color: viewModel.sortByPriority
? Colors.white
: AppColors.primaryBlue,
),
)
],
const SizedBox(width: 5),
Text(
'Sort',
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: viewModel.sortByPriority
? Colors.white
: AppColors.primaryBlue,
),
),
],
),
),
),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# First, let's check if the file exists and its size
wc -l src/lib/features/tasks/view/screens/home_screen.dart

Repository: tqha1011/TaskManagement

Length of output: 123


🏁 Script executed:

#!/bin/bash
# Read lines 149-190 to see the sort button implementation
sed -n '149,190p' src/lib/features/tasks/view/screens/home_screen.dart

Repository: tqha1011/TaskManagement

Length of output: 2032


🏁 Script executed:

#!/bin/bash
# Read lines 356-390 to see the _FilterChip implementation
sed -n '356,390p' src/lib/features/tasks/view/screens/home_screen.dart

Repository: tqha1011/TaskManagement

Length of output: 1029


🏁 Script executed:

#!/bin/bash
# Search for _FilterChip definition to understand its implementation
rg -A 20 'class _FilterChip|_FilterChip\(' src/lib/features/tasks/view/screens/home_screen.dart

Repository: tqha1011/TaskManagement

Length of output: 2294


🏁 Script executed:

#!/bin/bash
# Look at wider context around line 149 (from 140-200) to see parent widgets
sed -n '140,200p' src/lib/features/tasks/view/screens/home_screen.dart

Repository: tqha1011/TaskManagement

Length of output: 2763


🏁 Script executed:

#!/bin/bash
# Search for Material widgets in the file
rg -n 'Material\(' src/lib/features/tasks/view/screens/home_screen.dart

Repository: tqha1011/TaskManagement

Length of output: 49


🏁 Script executed:

#!/antml/bin
# Search for Semantics usage in the file
rg -n 'Semantics' src/lib/features/tasks/view/screens/home_screen.dart

Repository: tqha1011/TaskManagement

Length of output: 49


🏁 Script executed:

#!/bin/bash
# Search for GestureDetector to see all usages and their context
rg -B 2 -A 2 'GestureDetector' src/lib/features/tasks/view/screens/home_screen.dart | head -60

Repository: tqha1011/TaskManagement

Length of output: 429


🏁 Script executed:

#!/bin/bash
# Check if Material or Scaffold widget wraps the entire screen
sed -n '1,100p' src/lib/features/tasks/view/screens/home_screen.dart | grep -n -A 5 'build\|Scaffold\|Material'

Repository: tqha1011/TaskManagement

Length of output: 772


🏁 Script executed:

#!/bin/bash
# Look for any MaterialApp or Material widget context in the file
rg -n 'Scaffold|MaterialApp|Material' src/lib/features/tasks/view/screens/home_screen.dart | head -20

Repository: tqha1011/TaskManagement

Length of output: 142


🏁 Script executed:

#!/bin/bash
# Let's check the full structure around the build method to see the widget tree
sed -n '14,30p' src/lib/features/tasks/view/screens/home_screen.dart

Repository: tqha1011/TaskManagement

Length of output: 620


🏁 Script executed:

#!/bin/bash
# Check if there are any other interactive widgets in the file to compare patterns
rg -n 'InkWell|FilterChip|ChoiceChip' src/lib/features/tasks/view/screens/home_screen.dart

Repository: tqha1011/TaskManagement

Length of output: 245


Sort and filter controls need focusable/semantic widgets.

Both the sort button and _FilterChip are wired through GestureDetector, missing keyboard navigation, pressed states, and selected semantics. These are primary navigation controls on the screen—use FilterChip/ChoiceChip/InkWell inside Material instead.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/features/tasks/view/screens/home_screen.dart` around lines 149 - 190,
Replace the raw GestureDetector + AnimatedContainer used for the sort control
with a semantic, focusable Material widget such as FilterChip or ChoiceChip (or
wrap the AnimatedContainer with InkWell inside a Material) so it supports
keyboard navigation, focus/pressed states and accessibility semantics;
specifically change the GestureDetector that calls
viewModel.toggleSortByPriority() to use a FilterChip/ChoiceChip (or InkWell in
Material) and map its selected state to viewModel.sortByPriority and its
onSelected/onChanged to viewModel.toggleSortByPriority(), and do the same
replacement for the custom _FilterChip so both controls gain proper
focusability, pressed visuals and accessibility labels instead of relying on
GestureDetector.

Comment on lines +18 to +57
Row(
children: Priority.values.map((priority) {
final isSelected = viewModel.selectedPriority == priority;
return Expanded(
child: Padding(
padding: const EdgeInsets.only(right: 8),
child: GestureDetector(
onTap: () => viewModel.setPriority(priority),
child: AnimatedContainer(
duration: const Duration(milliseconds: 200),
padding: const EdgeInsets.symmetric(vertical: 10),
decoration: BoxDecoration(
color: isSelected
? priority.color
: const Color(0xFFF1F7FD),
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: isSelected ? priority.color : Colors.transparent,
),
),
child: Column(
children: [
Icon(
priority.icon,
color: isSelected ? Colors.white : priority.color,
size: 20,
),
const SizedBox(height: 4),
Text(
priority.label,
style: TextStyle(
fontSize: 11,
fontWeight: FontWeight.w600,
color: isSelected ? Colors.white : priority.color,
),
),
],
),
),
),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat -n src/lib/features/tasks/view/widgets/priority_selector.dart

Repository: tqha1011/TaskManagement

Length of output: 2892


🏁 Script executed:

rg -n "class Priority|enum Priority" src/lib/features/tasks/model/task_model.dart -A 20

Repository: tqha1011/TaskManagement

Length of output: 608


🏁 Script executed:

rg -n "Semantics|GestureDetector|InkWell" src/lib/features/tasks/view/widgets/priority_selector.dart

Repository: tqha1011/TaskManagement

Length of output: 109


🏁 Script executed:

rg -n "FocusNode|onKey|RawKeyboardListener|Focus\(" src/lib/features/tasks/view/widgets/priority_selector.dart

Repository: tqha1011/TaskManagement

Length of output: 49


🏁 Script executed:

rg -n "ChoiceChip|Radio\(" src/lib/features/tasks/view/widgets/ -t dart

Repository: tqha1011/TaskManagement

Length of output: 49


🏁 Script executed:

fd "priority_selector" src/lib/features/tasks/view/widgets/ -t f

Repository: tqha1011/TaskManagement

Length of output: 125


🏁 Script executed:

rg -n "Semantics|SemanticButton|selectableButton" src/lib/features/tasks/view/widgets/ -t dart

Repository: tqha1011/TaskManagement

Length of output: 49


Use an accessible selection control for priorities.

The priority options are implemented with GestureDetector without any semantics wrapper or keyboard support, making them inaccessible to screen readers and keyboard users. Replace with a proper selectable control such as ChoiceChip or Radio buttons, which provide keyboard navigation, semantic information, and Material interaction feedback automatically.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/features/tasks/view/widgets/priority_selector.dart` around lines 18 -
57, Replace the custom GestureDetector+AnimatedContainer implementation with a
proper selectable Material control (e.g., ChoiceChip) inside the
Priority.values.map so keyboard and screen-reader interaction are automatic; for
each priority, use ChoiceChip with selected: viewModel.selectedPriority ==
priority, onSelected: (_) => viewModel.setPriority(priority), avatar/icon using
priority.icon, label using priority.label, and apply selectedColor:
priority.color and backgroundColor: Color(0xFFF1F7FD) plus a rounded
shape/border to match the current visuals—this keeps the Priority.values
mapping, viewModel.setPriority, and viewModel.selectedPriority references while
providing built-in semantics and keyboard support.

Comment on lines +17 to +55
Wrap(
spacing: 8,
runSpacing: 8,
children: viewModel.availableTags.map((tag) {
final isSelected = viewModel.isTagSelected(tag);
return GestureDetector(
onTap: () => viewModel.toggleTag(tag),
child: AnimatedContainer(
duration: const Duration(milliseconds: 200),
padding: const EdgeInsets.symmetric(
horizontal: 14,
vertical: 8,
),
decoration: BoxDecoration(
color: isSelected
? tag.color
: tag.color.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(20),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
if (isSelected) ...[
const Icon(Icons.check, color: Colors.white, size: 14),
const SizedBox(width: 4),
],
Text(
tag.name,
style: TextStyle(
fontSize: 13,
fontWeight: FontWeight.w500,
color: isSelected ? Colors.white : tag.color,
),
),
],
),
),
);
}).toList(),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's locate and examine the tag_selector.dart file
find . -name "tag_selector.dart" -type f

Repository: tqha1011/TaskManagement

Length of output: 122


🏁 Script executed:

# Also search for priority_selector to understand the referenced comparison
find . -name "*priority*selector*" -type f

Repository: tqha1011/TaskManagement

Length of output: 127


🏁 Script executed:

# Read the tag_selector.dart file to see the full implementation
cat -n ./src/lib/features/tasks/view/widgets/tag_selector.dart

Repository: tqha1011/TaskManagement

Length of output: 2480


🏁 Script executed:

# Read the priority_selector.dart file to compare
cat -n ./src/lib/features/tasks/view/widgets/priority_selector.dart

Repository: tqha1011/TaskManagement

Length of output: 2892


🏁 Script executed:

# Check if there are any other uses of FilterChip in the codebase
rg "FilterChip" --type dart

Repository: tqha1011/TaskManagement

Length of output: 441


🏁 Script executed:

# Let's also check what Flutter version or material design widgets are being used
find . -name "pubspec.yaml" -type f | head -5

Repository: tqha1011/TaskManagement

Length of output: 85


🏁 Script executed:

# Check pubspec.yaml to see Flutter version and dependencies
cat -n ./src/pubspec.yaml

Repository: tqha1011/TaskManagement

Length of output: 4722


🏁 Script executed:

# Examine the home_screen.dart to see how _FilterChip is implemented
cat -n ./src/lib/features/tasks/view/screens/home_screen.dart | grep -A 50 "class _FilterChip"

Repository: tqha1011/TaskManagement

Length of output: 1294


🏁 Script executed:

# Let's search for any imports or usage of Flutter's Material FilterChip (not custom)
rg "from 'package:flutter/material.dart'" -A 5 ./src/lib/features/tasks/view/widgets/tag_selector.dart

Repository: tqha1011/TaskManagement

Length of output: 49


🏁 Script executed:

# Search for any Semantics or Focus handling in the codebase
rg "Semantics|Focus|FocusableActionDetector" --type dart | head -20

Repository: tqha1011/TaskManagement

Length of output: 2117


🌐 Web query:

Flutter Material FilterChip multi-select accessibility focus semantics

💡 Result:

  • Use FilterChip for true multi-select: it’s designed for selecting multiple filters; drive it with selected: and update state in onSelected:. [1]
  • Rely on built-in “button” semantics (don’t re-wrap unless you must): interactive Material chips (FilterChip included) are now exposed to assistive tech as buttons automatically, improving screen-reader behavior versus older Flutter versions. [2]
  • Ensure the chip’s label is meaningful to screen readers: prefer a plain Text('…') label; if you use non-textual/complex labels, add an explicit Semantics(label: ...) (or otherwise ensure an accessible label). (The chip being a button doesn’t guarantee a good label.) [2]
  • Make selection state discoverable: selection is typically conveyed via the semantics “selected” flag; if you build custom semantics around chips, ensure you expose a selected state (Flutter’s semantics model uses an isSelected flag). [3]
  • Keyboard focus & traversal (desktop/web/TV): chips participate in Flutter’s focus system; if you need predictable tab/arrow traversal across many chips, use FocusTraversalGroup + an ordering policy (or explicit FocusOrder) and per-chip FocusNodes. [4]

Sources: Flutter FilterChip API docs [1], Flutter breaking-change note on chip button semantics [2], Flutter semantics isSelected flag docs [3], Flutter focus system docs [4].


Replace GestureDetector with Flutter Material FilterChip for proper accessibility.

Tags use a multi-select pattern but wrap GestureDetector around custom widgets, which lacks semantic button role, focus handling, and selection state semantics. FilterChip automatically exposes selection state to screen readers and participates in the focus system, making it the correct choice here.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/features/tasks/view/widgets/tag_selector.dart` around lines 17 - 55,
Replace the custom GestureDetector + AnimatedContainer tag widgets with
Flutter's FilterChip to restore proper accessibility and focus/selection
semantics: in the Wrap over viewModel.availableTags (where you currently call
viewModel.isTagSelected(tag) and viewModel.toggleTag(tag)), render a FilterChip
per tag with selected set from viewModel.isTagSelected(tag), onSelected calling
viewModel.toggleTag(tag), label using Text(tag.name) and styling via
selectedColor (tag.color), backgroundColor (tag.color.withOpacity(0.1)),
labelStyle (use white when selected, tag.color when not), padding and shape
(BorderRadius.circular(20)) to match current visuals, and optionally provide a
selectedIcon (Icons.check) to mimic the existing check display.

@tqha1011 tqha1011 merged commit 35f0285 into main Apr 9, 2026
1 of 2 checks passed
tqha1011 added a commit that referenced this pull request Apr 18, 2026
* Feature/user profile (#30)

* feat(UserProfile): build screen UserProfile

# Conflicts:
#	src/lib/features/main/view/screens/main_screen.dart

* feat: switch dark/light theme

* fix: black color theme

* fix: black theme in statistics screen

* feat: add dark theme to auth screen

* feat: apply dark theme for bottom navigation bar

* feat(priority task):Implement priority and tag selection in task creation version 1 (#31)

* feat(task): implement priority and tag selection features in task creation

* Update README.md

* Update README.md

* Update README.md

---------

Co-authored-by: Tran Quang Ha <[email protected]>

* Update README.md (#32)

* feat: Priority selector and tag system verson2 (#33)

* feat(task): implement priority and tag selection features in task creation

* feat(tags): enhance tag management with custom tag creation and selection

* Update README.md

* Update README.md

* fix: error screen in main.dart (#34)

* Enhance authentication UI and implement Focus feature set (#35)

* feat(core): add auth layout template, custom textfield and colors

* feat(auth): implement viewmodels for auth flow (MVVM)

* feat(auth): build complete auth UI screens (Login, Register, OTP, Passwords)

* chore(main): set LoginView as initial route

* refactor(auth) : delete .gitkeep

* chore: update dependencies and pubspec.lock

* refactor(auth): optimize registration logic, timezone handling, and form validation

* feat(auth): update UI for login, registration, and forgot password screens

* feat(tasks): update task management UI and statistics screen

* chore: update main entry point and fix widget tests

* chore: ignore devtools_options.yaml

* chore: ignore devtools_options.yaml

* style(login) : rewrite title for login view

* feat(auth): configure android deep link for supabase oauth

* refactor(ui): add social login callbacks to auth layout template

* feat(auth): update oauth methods with redirect url and signout

* feat(auth): implement AuthGate using StreamBuilder for session tracking

* feat(viewmodel): add oauth logic and improve provider lifecycle

* refactor(ui): migrate LoginView to Provider pattern

* chore(main): set AuthGate as initial route and setup provider

* feat: implement full Focus feature set

- Added Pomodoro timer with Start/Reset/Skip logic.
- Integrated local Quick Notes with Pin/Delete functionality.
- Supported image attachments in notes using image_picker.
- Added Focus settings: time duration, vibration, and ringtones.

* fix (auth) : dispose TextEditingControllers to prevent memory leaks

* refactor (alarm ) : create off alarm button  when time out

* fix: apply CodeRabbit auto-fixes

Fixed 3 file(s) based on 4 unresolved review comments.

Co-authored-by: CodeRabbit <[email protected]>

* fix(timer): prevent division by zero in progress calculation and sanitize negative settings input

* fix(timer): prevent division by zero in progress calculation and sanitize negative settings input

* fix(auth): unblock new-user login and add settings logout

* refactor(LoginScreen) : compact all items to fit in screen to help users interface easily

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: CodeRabbit <[email protected]>

* build(deps)(deps): bump shared_preferences from 2.5.4 to 2.5.5 in /src (#36)

Bumps [shared_preferences](https://github.com/flutter/packages/tree/main/packages/shared_preferences) from 2.5.4 to 2.5.5.
- [Commits](https://github.com/flutter/packages/commits/shared_preferences-v2.5.5/packages/shared_preferences)

---
updated-dependencies:
- dependency-name: shared_preferences
  dependency-version: 2.5.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Feature/user profile (#37)

* feat(UserProfile): build screen UserProfile

# Conflicts:
#	src/lib/features/main/view/screens/main_screen.dart

* feat: switch dark/light theme

* fix: black color theme

* fix: black theme in statistics screen

* feat: add dark theme to auth screen

* feat: apply dark theme for bottom navigation bar

* feat(RPC): update RPC to get data for heatmap

* feat(RPC): update new RPC to get data for heatmap

* feat: integrate chatbot assistant

* feat(chatbot): integrate create task, answer question for chatbot

* feat: remove mock data and get data tags and categories from supabase

* feat: integrate chatbot's ability to create task

---------

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: Nguyễn Anh Kiệt <[email protected]>
Co-authored-by: Nguyễn Lê Hoàng Hảo <[email protected]>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: CodeRabbit <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
@coderabbitai coderabbitai Bot mentioned this pull request Apr 18, 2026
tqha1011 added a commit that referenced this pull request Apr 18, 2026
* feat: add create task screen and fix home screen provider errors

* Feature/user profile (#30)

* feat(UserProfile): build screen UserProfile

# Conflicts:
#	src/lib/features/main/view/screens/main_screen.dart

* feat: switch dark/light theme

* fix: black color theme

* fix: black theme in statistics screen

* feat: add dark theme to auth screen

* feat: apply dark theme for bottom navigation bar

* feat(priority task):Implement priority and tag selection in task creation version 1 (#31)

* feat(task): implement priority and tag selection features in task creation

* Update README.md

* Update README.md

* Update README.md

---------

Co-authored-by: Tran Quang Ha <[email protected]>

* Remove comment about main UI in home_screen.dart

Removed commented section about main UI.

* Update README.md (#32)

* feat: Priority selector and tag system verson2 (#33)

* feat(task): implement priority and tag selection features in task creation

* feat(tags): enhance tag management with custom tag creation and selection

* Update README.md

* Update README.md

* fix: error screen in main.dart (#34)

* Enhance authentication UI and implement Focus feature set (#35)

* feat(core): add auth layout template, custom textfield and colors

* feat(auth): implement viewmodels for auth flow (MVVM)

* feat(auth): build complete auth UI screens (Login, Register, OTP, Passwords)

* chore(main): set LoginView as initial route

* refactor(auth) : delete .gitkeep

* chore: update dependencies and pubspec.lock

* refactor(auth): optimize registration logic, timezone handling, and form validation

* feat(auth): update UI for login, registration, and forgot password screens

* feat(tasks): update task management UI and statistics screen

* chore: update main entry point and fix widget tests

* chore: ignore devtools_options.yaml

* chore: ignore devtools_options.yaml

* style(login) : rewrite title for login view

* feat(auth): configure android deep link for supabase oauth

* refactor(ui): add social login callbacks to auth layout template

* feat(auth): update oauth methods with redirect url and signout

* feat(auth): implement AuthGate using StreamBuilder for session tracking

* feat(viewmodel): add oauth logic and improve provider lifecycle

* refactor(ui): migrate LoginView to Provider pattern

* chore(main): set AuthGate as initial route and setup provider

* feat: implement full Focus feature set

- Added Pomodoro timer with Start/Reset/Skip logic.
- Integrated local Quick Notes with Pin/Delete functionality.
- Supported image attachments in notes using image_picker.
- Added Focus settings: time duration, vibration, and ringtones.

* fix (auth) : dispose TextEditingControllers to prevent memory leaks

* refactor (alarm ) : create off alarm button  when time out

* fix: apply CodeRabbit auto-fixes

Fixed 3 file(s) based on 4 unresolved review comments.

Co-authored-by: CodeRabbit <[email protected]>

* fix(timer): prevent division by zero in progress calculation and sanitize negative settings input

* fix(timer): prevent division by zero in progress calculation and sanitize negative settings input

* fix(auth): unblock new-user login and add settings logout

* refactor(LoginScreen) : compact all items to fit in screen to help users interface easily

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: CodeRabbit <[email protected]>

* build(deps)(deps): bump shared_preferences from 2.5.4 to 2.5.5 in /src (#36)

Bumps [shared_preferences](https://github.com/flutter/packages/tree/main/packages/shared_preferences) from 2.5.4 to 2.5.5.
- [Commits](https://github.com/flutter/packages/commits/shared_preferences-v2.5.5/packages/shared_preferences)

---
updated-dependencies:
- dependency-name: shared_preferences
  dependency-version: 2.5.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Feature/user profile (#37)

* feat(UserProfile): build screen UserProfile

# Conflicts:
#	src/lib/features/main/view/screens/main_screen.dart

* feat: switch dark/light theme

* fix: black color theme

* fix: black theme in statistics screen

* feat: add dark theme to auth screen

* feat: apply dark theme for bottom navigation bar

* feat(RPC): update RPC to get data for heatmap

* feat(RPC): update new RPC to get data for heatmap

* feat: integrate chatbot assistant

* feat(chatbot): integrate create task, answer question for chatbot

* feat: remove mock data and get data tags and categories from supabase

* fixed codes, added save delete and create tasks and notes

* Delete .vs/TaskManagement.slnx/v18/.wsuo

* Delete .vs directory

* Delete .vscode directory

* Delete src/.gitignore

* Delete src/lib/features/auth/viewmodels/task_provider.dart

* Delete src/web_entrypoint.dart

---------

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: Tran Quang Ha <[email protected]>
Co-authored-by: Nguyễn Anh Kiệt <[email protected]>
Co-authored-by: Nguyễn Lê Hoàng Hảo <[email protected]>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: CodeRabbit <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
@tqha1011 tqha1011 deleted the priority_selector_and_tag_system branch April 20, 2026 12:29
@tqha1011 tqha1011 restored the priority_selector_and_tag_system branch April 20, 2026 12:29
@tqha1011 tqha1011 deleted the priority_selector_and_tag_system branch April 20, 2026 12:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants